package com.hb.config;

import com.hb.domain.Spitter;
import com.hb.domain.Spittle;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;

import javax.sql.DataSource;
import java.util.Properties;

@Configuration
public class Hibernate4Config {
    /**
     * 如果你使用 Hibernate 4 的话，那么就应该使用 org.springframework.orm.hibernate4 中的 LocalSessionFactoryBean。尽管它与 Hibernate 3 包中的
     * LocalSessionFactoryBean 使用了相同的名称，但是 Spring 3.1 新引入的这个 Session 工厂类似于 Hibernate 3 中 LocalSessionFactoryBean 和 AnnotationSessionFactoryBean
     * 的结合体。它有很多相同的属性，能够支持基于 XML 的映射和基于注解的映射
     *
     * @param dataSource
     * @return
     */
    @Bean
    public LocalSessionFactoryBean sessionFactoryBean(DataSource dataSource) {
        // 这里不再列出 Hibernate 配置文件，而是使用 packagesToScan 属性告诉 Spring 扫描一个或多个包以查找域类，这些类通过注解的方式表明要使用 Hibernate 进行持久化，
        // 这些类可以使用的注解包括 JPA 的 @Entity 或 @MappedSuperclass 以及 Hibernate 的 @Entity。
        // Hibernate 4 无法使用 XML 配置映射？
        LocalSessionFactoryBean sfb = new LocalSessionFactoryBean();
        sfb.setDataSource(dataSource);
        sfb.setPackagesToScan("com.hb.domain");
        // 如果愿意的话，你还可以使用 annotatedClasses 属性来将应用程序中所有的持久化类以全限定名的方式明确列出。annotatedClasses 属性对于准确指定少量的域类是不错的选择。
        // 如果你有很多的域类并且不想将其全部列出，又或者你想自由地添加或移除域类而不想修改 Spring 配置的话，那使用 packagesToScan 属性是更合适的。
        sfb.setAnnotatedClasses(new Class<?>[]{Spitter.class, Spittle.class});
        Properties props = new Properties();
        props.setProperty("dialect", "org.hibernate.dialect.H2Dialect");
        sfb.setHibernateProperties(props);
        return sfb;
    }

    /**
     * 为了给不使用模板（HibernateTemplate）的 Hibernate Repository 添加异常转换功能，我们只需在 Spring 应用上下文中添加一个 PersistenceExceptionTranslationPostProcessor bean。
     * PersistenceExceptionTranslationPostProcessor 是一个 bean 后置处理器（bean post-processor），它会在所有拥有 @Repository 注解的类上添加一个通知器（advisor）， 这样就会
     * 捕获任何平台相关的异常并以 Spring 非检查型数据访问异常的形式重新抛出。
     * @return
     */
    @Bean
    public BeanPostProcessor persistenceTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }
}
